/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 default_artifacts.cpp

	$Header: /heroes4/default_artifacts.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "default_artifacts.h"

#include "alignment_relationship.h"
#include "artifact_prop_ability.h"
#include "artifact_prop_aligned_bonus.h"
#include "artifact_prop_combat.h"
#include "artifact_prop_damage.h"
#include "artifact_prop_fragment.h"
#include "artifact_prop_growth.h"
#include "artifact_prop_income.h"
#include "artifact_prop_movement.h"
#include "artifact_prop_single_spell.h"
#include "artifact_prop_skill.h"
#include "artifact_prop_spell_attack.h"
#include "artifact_prop_spell_charges.h"
#include "artifact_prop_spell_cost.h"
#include "artifact_type.h"
#include "creature_ability.h"
#include "default_artifact_properties.h"
#include "elements_of.h"
#include "enum_operations.h"
#include "external_string.h"
#include "format_string.h"
#include "hero_class.h"
#include "keyword_replacer.h"
#include "replace_keywords.h"
#include "sized_int_types.h"
#include "skill.h"
#include "spell.h"
#include "spell_properties.h"
#include "streambuf_operators.h"
#include "terrain.h"
#include "town_type.h"

namespace
{
	struct t_artifact_definition : public t_counted_object
	{
		t_artifact_effect_list effects;

		t_artifact_definition()
		{
		}

		t_artifact_definition( t_artifact_effect* effect )
		{
			effects.push_back( effect );
		}
	};

	class t_trait_base
	{
	public:
		t_trait_base();
		t_trait_base( t_artifact_effect* effect );

		t_artifact_effect_list const& get_effects() const;
		t_artifact_type				  get_type() const;

		t_trait_base operator << ( t_artifact_effect* effect );
		t_trait_base operator << ( t_trait_base const& arg );
	protected:
		t_artifact_type							m_type;
		t_counted_ptr<t_artifact_definition>	m_definition;
	};

	inline t_trait_base::t_trait_base()
	{
		m_definition = new t_artifact_definition;
	}

	inline t_trait_base::t_trait_base( t_artifact_effect* effect )
	{
		m_definition = new t_artifact_definition( effect );
	}

	inline t_artifact_effect_list const& t_trait_base::get_effects() const
	{
		return m_definition->effects;
	}

	inline t_trait_base t_trait_base::operator << ( t_artifact_effect* effect )
	{
		m_definition->effects.push_back( effect );
		return *this;
	}

	t_trait_base t_trait_base::operator << ( t_trait_base const& arg )
	{
		t_artifact_effect_list::const_iterator index = arg.get_effects().begin();
		t_artifact_effect_list::const_iterator end = arg.get_effects().end();

		for (; index != end; ++index)
			m_definition->effects.push_back( *index );
		return *this;
	}


	template<class t_type>
	class t_artifact_trait : public t_trait_base
	{
	public:
		t_artifact_trait();
		t_artifact_trait( t_type type );
		t_artifact_trait( t_type type, t_artifact_effect* effect );
		t_artifact_trait( t_type type, t_trait_base trait );

		t_type				  get_type() const;

		t_artifact_trait operator << ( t_artifact_effect* effect );
		t_artifact_trait operator << ( t_trait_base const& arg );
	protected:
		t_type							m_type;
	};
	
	template<class t_type>
	inline t_artifact_trait<t_type>::t_artifact_trait()
	{
		m_type = k_artifact_none;
	}

	template<class t_type>
	inline t_artifact_trait<t_type>::t_artifact_trait( t_type type )
	{
		m_type = type;
	}
	
	template<class t_type>
	inline t_artifact_trait<t_type>::t_artifact_trait( t_type type, t_artifact_effect* effect )
			      : t_trait_base( effect )
	{
		m_type = type;
		m_definition = new t_artifact_definition( effect );
	}

	template<class t_type>
	inline t_artifact_trait<t_type>::t_artifact_trait( t_type type, t_trait_base trait )
		          : t_trait_base( trait )
	{
		m_type = type;
	}

	template<class t_type>
	inline t_type t_artifact_trait<t_type>::get_type() const
	{
		return m_type;
	}


	template<class t_type>
	t_artifact_trait<t_type> t_artifact_trait<t_type>::operator << ( t_artifact_effect* effect )
	{
		t_trait_base::operator << (effect);
		return *this;
	}

	template<class t_type>
	t_artifact_trait<t_type> t_artifact_trait<t_type>::operator << ( t_trait_base const& arg )
	{
		t_trait_base::operator << ( arg );
		return *this;
	}

	typedef t_artifact_trait<t_artifact_type> t_trait;
};


// ---------------------------------------------------------
// get a spell book which contains all spells of a level 
// ---------------------------------------------------------
static t_artifact_effect* get_spell_book( int level )
{
	t_artifact_prop::t_spell_book* list 
		= new t_artifact_prop::t_spell_book( k_artifact_target_hero );
	t_spell                       spell;

	for (spell = t_spell(0); spell < k_spell_count; enum_incr(spell))
		if (get_spell_level( spell ) == level && is_teachable( spell ))
			list->add( spell );
	return list;
}

// ---------------------------------------------------------
// get a spell book which contains all spells of an alignment
// ---------------------------------------------------------
static t_artifact_effect* get_spell_book( t_town_type alignment )
{
	t_artifact_prop::t_spell_book* list 
		= new t_artifact_prop::t_spell_book( k_artifact_target_hero );
	t_spell                       spell;

	for (spell = t_spell(0); spell < k_spell_count; enum_incr(spell))
		if (get_spell_alignment( spell ) == alignment && is_teachable( spell ))
			list->add( spell );
	return list;
}

// ---------------------------------------------------------
// get health boost
// ---------------------------------------------------------
static t_artifact_effect* get_health( int amount )
{
	return new t_artifact_prop::t_health( k_artifact_target_hero, amount );
}

// ---------------------------------------------------------
// get armor 
// ---------------------------------------------------------
static t_artifact_effect* get_armor( int amount )
{
	return new t_artifact_prop::t_defense( true, true, k_artifact_target_hero, amount );
}

// ---------------------------------------------------------
// get a shield
// ---------------------------------------------------------
static t_artifact_effect* get_defense( int amount )
{
	return new t_artifact_prop::t_defense( true, true, 
		                                   k_artifact_target_friendly_creatures, amount );
}


// ---------------------------------------------------------
// get a shield
// ---------------------------------------------------------
static t_trait get_shield( int amount )
{
	t_trait            trait;

	trait << get_defense( amount );
	trait << get_armor( 30 );
	return trait;
}

// ---------------------------------------------------------
// get spell effect
// ---------------------------------------------------------
static t_artifact_effect* get_spell_effect( t_spell spell, 
										    t_artifact_target target = k_artifact_target_hero,
										    int amount = 0 )
{
	return new t_artifact_prop::t_spell_effect( spell, target, amount );
}

// ---------------------------------------------------------
// get armor with +50% HP and a spell
// ---------------------------------------------------------
static t_trait_base get_magic_armor( t_spell spell )
{
	return t_trait_base() << get_armor( 200 ) << get_spell_effect( spell, k_artifact_target_hero );
}

// ---------------------------------------------------------
// get shield with +25% HP and a spell
// ---------------------------------------------------------
static t_trait_base get_magic_shield( t_spell spell )
{
	return t_trait_base() << get_shield( 30 ) 
					 << get_spell_effect( spell, k_artifact_target_friendly_creatures );
}

// ---------------------------------------------------------
// get a piece of the statue of legion
// ---------------------------------------------------------
static t_artifact_effect* get_statue( int amount )
{
	int                                 i;
	t_artifact_prop::t_creature_growth* growth;

	growth = new t_artifact_prop::t_creature_growth;
	for (i = 0; i < k_creature_level_count; i++)
		growth->set_bonus( i, amount );
	return growth;
}

// ---------------------------------------------------------
// get a piece of the statue of legion
// ---------------------------------------------------------
static t_trait get_statue_piece( int level, int amount )
{
	t_trait					            result;
	t_artifact_prop::t_creature_growth* growth;

	result << new t_artifact_prop::t_fragment( k_artifact_statue_of_legion, 4 );
	growth = new t_artifact_prop::t_creature_growth;
	growth->set_bonus( level, amount );
	result << growth;
	return result;
}

// ---------------------------------------------------------
// set spells of a given type
// ---------------------------------------------------------
void add_spells( t_artifact_prop::t_spell_list_effect* list, int bits )
{
	t_spell spell;

	for (spell = t_spell(0); spell != k_spell_count; enum_incr( spell ))
		if (spell_is( spell, bits ))
			list->add( spell );
}

// ---------------------------------------------------------
// get badge of courage
// ---------------------------------------------------------
static t_trait get_badge_of_courage()
{
	t_trait				         result( k_artifact_badge_of_courage );
	t_artifact_prop::t_immunity* list;

	list = new t_artifact_prop::t_immunity( k_artifact_target_friendly_creatures, 0 );
	add_spells( list, k_spell_bit_fear );
	result << list;
	return result;
};

// ---------------------------------------------------------
// get income artifact
// ---------------------------------------------------------
static t_artifact_effect* get_income( t_material material, int amount )
{
	return new t_artifact_prop::t_income( material, amount );
}

// ---------------------------------------------------------
// get supreme alignment artifact
// ---------------------------------------------------------
static t_trait_base get_supreme_artifact( t_town_type alignment, t_spell spell_1, t_spell spell_2 )
{
	t_trait_base result;

	// add bonuses to aligned creatures
	result << new t_artifact_prop::t_aligned_bonus( alignment, 50, 50, 2, 
		                                            k_artifact_target_everything );
	// add penalties to hostile creatures
	t_town_type index;

	for (index = t_town_type(0); index != k_town_type_count; enum_incr( index ))
	{
		if (get_alignment_relationship( alignment, index ) != k_alignments_hostile)
			continue;

		result << new t_artifact_prop::t_aligned_bonus( index, -33, -33, -2, 
		                                                k_artifact_target_everything );
	}
	// add "protection from" effects
	result << new t_artifact_prop::t_spell_effect( spell_1, 
										            k_artifact_target_everything, 0);
	result << new t_artifact_prop::t_spell_effect( spell_2, k_artifact_target_everything, 0 );
	// add spell cost bonus
	t_artifact_prop::t_spell_cost*  cost;
	t_artifact_prop::t_spell_bonus* list;
	t_spell                         spell;

	cost = new t_artifact_prop::t_spell_cost( k_artifact_target_everything, 0, -50 );
	list = new t_artifact_prop::t_spell_bonus( k_artifact_target_everything, 100 );
	for (spell = t_spell(0); spell != k_spell_count; enum_incr( spell ))
	{
		if (get_spell_alignment( spell ) != alignment)
			continue;
		if (has_strength( spell ))
			list->add( spell );
		else
			cost->add( spell );
	}
	return result << list << cost;
}

// ---------------------------------------------------------
// get might supreme alignment artifact
// ---------------------------------------------------------
static t_trait get_shield_of_resistance() 
{
	t_trait result;

	// add bonuses to aligned creatures
	result << new t_artifact_prop::t_aligned_bonus( k_town_might, 50, 50, 2, 
		                                            k_artifact_target_everything );
	// add penalties to hostile creatures
	t_town_type index;

	for (index = t_town_type(0); index != k_town_type_count; enum_incr( index ))
	{
		if (index == k_town_might)
			continue;

		result << new t_artifact_prop::t_aligned_bonus( index, -33, -33, -2, 
		                                                k_artifact_target_everything );
	}
	// add "protection from" effects
	result << new t_artifact_prop::t_spell_effect( k_spell_protection_from_life, 
										            k_artifact_target_everything,
												    0 );
	result << new t_artifact_prop::t_spell_effect( k_spell_protection_from_order, 
										            k_artifact_target_everything,
												    0 );
	result << new t_artifact_prop::t_spell_effect( k_spell_protection_from_death, 
										            k_artifact_target_everything,
												    0 );
	result << new t_artifact_prop::t_spell_effect( k_spell_protection_from_chaos, 
										            k_artifact_target_everything,
												    0 );
	result << new t_artifact_prop::t_spell_effect( k_spell_protection_from_nature, 
										            k_artifact_target_everything,
												    0 );

	t_artifact_prop::t_immunity* immunity;

	immunity = new t_artifact_prop::t_immunity( k_artifact_target_everything );
	add_spells( immunity, k_spell_bit_teachable );
	result << immunity;
	result << get_armor( 30 );
	return result;
}

// ---------------------------------------------------------
// get caduceus
// ---------------------------------------------------------
static t_trait get_caduceus()
{
	t_trait result( k_artifact_caduceus );

	result <<  new t_artifact_prop::t_skill_percentage( k_skill_resurrection, 20 );
	t_artifact_prop::t_spell_bonus* list;
	t_spell                         spell;

	list = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, 100 );
	for (spell = t_spell(0); spell != k_spell_count; enum_incr( spell ))
	{
		if (has_strength( spell ) && is_healing( spell ))
			list->add( spell );
	}
	result << list;
	return result;
}

// ---------------------------------------------------------
// get an effect which alters all spell costs
// ---------------------------------------------------------
t_artifact_effect* get_spell_cost_effect( t_artifact_target target, int amount, int percentage )
{
	t_artifact_prop::t_spell_cost* cost;

	cost = new t_artifact_prop::t_spell_cost( target, amount, percentage );

	t_spell spell;

	for (spell = t_spell(0); spell != k_spell_count; enum_incr( spell ))
		cost->add( spell );
	return cost;
}


// ---------------------------------------------------------
// get artifact fragment
// ---------------------------------------------------------
static t_artifact_effect* get_fragment( t_artifact_type whole, int pieces )
{
	return new t_artifact_prop::t_fragment( whole, pieces );
}


// ---------------------------------------------------------
// get mana artifact
// ---------------------------------------------------------
static t_trait get_mana( int mana, int recharge )
{
	t_trait result;

	result << new t_artifact_prop::t_mana_maximum( k_artifact_target_hero, mana );
	result << new t_artifact_prop::t_mana_recharge( k_artifact_target_hero, recharge );
	return result;
};

// ---------------------------------------------------------
// get adventure movement artifact
// ---------------------------------------------------------
static t_artifact_effect* get_movement( int amount, bool land, bool sea )
{
	return new t_artifact_prop::t_adventure_movement( amount, land, sea );
}

// ---------------------------------------------------------
// get adventure weapon
// ---------------------------------------------------------
static t_artifact_effect* get_weapon( bool melee, bool ranged, int amount )
{
	return new t_artifact_prop::t_weapon( melee, ranged, k_artifact_target_hero, amount );
}

// ---------------------------------------------------------
// get a defense effect
// ---------------------------------------------------------
static t_artifact_effect* get_defense( bool melee, bool ranged, t_artifact_target target, 
									   int amount = 0 )
{
	return new t_artifact_prop::t_defense( melee, ranged, target, amount );
}

// ---------------------------------------------------------
// get a melee weapon with defensive abilities
// ---------------------------------------------------------
static t_trait get_sword( int attack, int defense )
{
	t_trait result;

	result << get_weapon( true, false, attack );
	result << get_defense( true, false, k_artifact_target_hero, defense );

	return result;
}

// ---------------------------------------------------------
// get adventure weapon
// ---------------------------------------------------------
static t_artifact_effect* get_magic_weapon( int amount, int bonus, int levels_per_bonus,
						                    bool melee, bool ranged, 
									        t_damage_type damage_type = k_damage_normal )
{
	return new t_artifact_prop::t_damage_bonus( amount, bonus, levels_per_bonus,
		                                        melee, ranged, damage_type );
}

// ---------------------------------------------------------
// get spell charges
// ---------------------------------------------------------
static t_artifact_effect* get_spell_charges(  t_spell spell, int charges = 1, int charge_rate = 2 )
{
	return new t_artifact_prop::t_spell_charges( spell, charges, charge_rate );
}

// ---------------------------------------------------------
// get potion
// ---------------------------------------------------------
static t_artifact_effect* get_potion( t_spell spell )
{
	return new t_artifact_prop::t_spell_charges( spell, 1, 0 );
}

// ---------------------------------------------------------
// get enchanted item
// ---------------------------------------------------------
static t_artifact_effect* get_spell_attack( t_spell spell, bool melee, bool ranged, 
										    int chance = 100  )
{
	return new t_artifact_prop::t_spell_with_attack( spell, melee, ranged, chance );
}

// ---------------------------------------------------------
// get a skill percentage increase
// ---------------------------------------------------------
static t_artifact_effect* get_skill( t_skill_type skill, int percentage )
{
	return new t_artifact_prop::t_skill_percentage( skill, percentage );
}

// ---------------------------------------------------------
// get a speed effect
// ---------------------------------------------------------
static t_artifact_effect* get_speed( t_artifact_target target, int amount )
{
	return new t_artifact_prop::t_speed( target, amount);
}

// ---------------------------------------------------------
// get a damage effect
// ---------------------------------------------------------
static t_artifact_effect* get_damage( int amount )
{
	return new t_artifact_prop::t_damage( k_artifact_target_friendly_creatures, amount );
}

// ---------------------------------------------------------
// get magic resistance
// ---------------------------------------------------------
static t_artifact_effect* get_resistance( t_artifact_target target, int amount )
{
	return new t_artifact_prop::t_resistance( target, amount );
}

// ---------------------------------------------------------
// get combat movement
// ---------------------------------------------------------
static t_artifact_effect* get_combat_movement( t_artifact_target target, int amount )
{
	return new t_artifact_prop::t_combat_movement( target, amount );
}

// ---------------------------------------------------------
// get a morale change
// ---------------------------------------------------------
static t_trait get_morale( int amount )
{
	t_trait result;

	result << new t_artifact_prop::t_morale( k_artifact_target_hero, amount );
	result << new t_artifact_prop::t_morale( k_artifact_target_friendly_heroes, amount );
	result << new t_artifact_prop::t_morale( k_artifact_target_friendly_creatures, amount );
	return result;
}

// ---------------------------------------------------------
// get a luck change
// ---------------------------------------------------------
static t_trait get_luck( int amount )
{
	t_trait result;

	result << new t_artifact_prop::t_luck( k_artifact_target_hero, amount );
	result << new t_artifact_prop::t_luck( k_artifact_target_friendly_heroes, amount );
	result << new t_artifact_prop::t_luck( k_artifact_target_friendly_creatures, amount );
	return result;
}

// ---------------------------------------------------------
// get scouting
// ---------------------------------------------------------
static t_artifact_effect* get_scouting( int amount )
{
	return new t_artifact_prop::t_scouting( k_artifact_target_hero, amount );
}

// ---------------------------------------------------------
// get immunity to a spell
// ---------------------------------------------------------
static t_artifact_effect* get_immunity( t_spell spell, t_artifact_target target )
{
	t_artifact_prop::t_immunity* effect
		 = new t_artifact_prop::t_immunity( target, 0 );

	effect->add( spell );
	return effect;
}

// ---------------------------------------------------------
// get immunity to a spell
// ---------------------------------------------------------
static t_trait get_immunity( t_spell spell )
{
	t_trait result;

	result << get_immunity( spell, k_artifact_target_friendly_creatures );
	result << get_immunity( spell, k_artifact_target_friendly_heroes );
	result << get_immunity( spell, k_artifact_target_hero );
	return result;
}

// ---------------------------------------------------------
// get immunity to a spell
// ---------------------------------------------------------
static t_trait get_mind_shield()
{
	t_trait result;

	t_artifact_prop::t_immunity* effect
		 = new t_artifact_prop::t_immunity( k_artifact_target_hero );

	add_spells( effect, k_spell_bit_mind );
	result << effect;

	effect = new t_artifact_prop::t_immunity( k_artifact_target_friendly_creatures, 0 );
	add_spells( effect, k_spell_bit_mind );
	result << effect;

	effect = new t_artifact_prop::t_immunity( k_artifact_target_friendly_heroes, 0);
	add_spells( effect, k_spell_bit_mind );
	result << effect;
	return result;
}

// ---------------------------------------------------------
// get the Ring of Permanency
// ---------------------------------------------------------
static void add_ring_of_permanency( t_artifact_prop::t_immunity* effect )
{
	effect->add( k_spell_dispel );
	effect->add( k_spell_mass_dispel );
	effect->add( k_spell_cancellation );
	effect->add( k_spell_mass_cancellation );
	effect->add( k_spell_steal_enchantment );
	effect->add( k_spell_steal_all_enchantments );
}

// ---------------------------------------------------------
// get the Ring of Permanency
// ---------------------------------------------------------
static t_trait get_ring_of_permanency()
{
	t_trait result;

	t_artifact_prop::t_immunity* effect
		 = new t_artifact_prop::t_immunity( k_artifact_target_hero );

	add_ring_of_permanency( effect );
	result << effect;

	effect = new t_artifact_prop::t_immunity( k_artifact_target_friendly_creatures, 0 );
	add_ring_of_permanency( effect );
	result << effect;

	effect = new t_artifact_prop::t_immunity( k_artifact_target_friendly_heroes, 0 );
	add_ring_of_permanency( effect );
	result << effect;

	return result;
}

// ---------------------------------------------------------
// get terrain mastery
// ---------------------------------------------------------
t_artifact_prop::t_terrain_mastery* get_terrain( t_terrain_type terrain )
{
	return new t_artifact_prop::t_terrain_mastery( k_artifact_target_hero, terrain );
}

// ---------------------------------------------------------
// get demonary
// ---------------------------------------------------------
static t_artifact_effect* get_demonary( int amount = 100 )
{
	t_artifact_prop::t_spell_bonus* bonus;

	bonus = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, amount );

	bonus->add( k_spell_summon_imps );
	bonus->add( k_spell_summon_cerberi );
	bonus->add( k_spell_summon_venom_spawn );
	bonus->add( k_spell_summon_devils );
	bonus->add( k_spell_summon_ice_demon );
	return bonus;
}

// ---------------------------------------------------------
// get elemental ring
// ---------------------------------------------------------
static t_artifact_effect* get_elemental_ring()
{
	t_artifact_prop::t_spell_bonus* bonus;

	bonus = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, 100 );
	bonus->add( k_spell_summon_air_elemental );
	bonus->add( k_spell_summon_earth_elemental );
	bonus->add( k_spell_summon_fire_elemental );
	bonus->add( k_spell_summon_water_elemental );
	return bonus;
}

// ---------------------------------------------------------
// get parchment properties
// ---------------------------------------------------------
static t_artifact_effect* get_parchment_effect( t_spell spell )
{
	return new t_artifact_prop::t_learn_spell( spell, k_artifact_target_hero );
}

// ---------------------------------------------------------
// get scroll properties
// ---------------------------------------------------------
static t_trait get_scroll( t_spell spell )
{
	t_trait							result( k_artifact_scroll );
	t_artifact_prop::t_spell_cost*	cost;

	result << new t_artifact_prop::t_cast_spell( spell, k_artifact_target_hero );
	cost = new t_artifact_prop::t_spell_cost( k_artifact_target_hero, 0, -50 );
	cost->add( spell );
	result << cost;
	return result;
}

// ---------------------------------------------------------
// get effect: summoning scarab
// ---------------------------------------------------------
static t_artifact_effect* get_summoning_scarab()
{
	t_artifact_prop::t_spell_bonus* result;

	result = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, 100 );
	add_spells( result, k_spell_bit_summoning );
	return result;
}

// ---------------------------------------------------------
// get effect: staff of death
// ---------------------------------------------------------
static t_artifact_effect* get_staff_of_death()
{
	t_artifact_prop::t_spell_bonus* result;

	result = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, 50 );

	result->add( k_spell_poison );
	result->add( k_spell_raise_ghost );
	result->add( k_spell_raise_skeletons );
	result->add( k_spell_raise_vampires );
	result->add( k_spell_animate_dead );
	result->add( k_spell_life_drain );
	result->add( k_spell_plague );
	result->add( k_spell_death_call );
	result->add( k_spell_hand_of_death );
	return result;
}

// ---------------------------------------------------------
// get effect: staff of enchantment
// ---------------------------------------------------------
static t_artifact_effect* get_staff_of_enchantment()
{
	t_artifact_prop::t_spell_cost* list;
	t_spell                        spell;

	list = new t_artifact_prop::t_spell_cost( k_artifact_target_hero, 0, -50 );
	for (spell = t_spell(0); spell != k_spell_count; enum_incr( spell ))
	{
		if (get_spell_alignment( spell ) == k_town_order && is_teachable( spell ))
			list->add( spell );
	}
	return list;
}
	
// ---------------------------------------------------------
// get effect: staff of summoning
// ---------------------------------------------------------
static t_artifact_effect* get_staff_of_summoning()
{
	t_artifact_prop::t_spell_cost* list;

	list = new t_artifact_prop::t_spell_cost( k_artifact_target_hero, 0, -50 );
	add_spells( list, k_spell_bit_summoning );
	return list;
}

// ---------------------------------------------------------
// get effect: staff of the witch king
// ---------------------------------------------------------
static t_artifact_effect* get_staff_of_the_witch_king()
{
	t_artifact_prop::t_spell_bonus* list;
	
	list = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, 50 );

	list->add( k_spell_magic_arrow );
	list->add( k_spell_burning_hands );
	list->add( k_spell_firebreathing );
	list->add( k_spell_fire_bolt );
	list->add( k_spell_fire_ring );
	list->add( k_spell_lightning );
	list->add( k_spell_implosion );
	list->add( k_spell_inferno );
	list->add( k_spell_armageddon );
	list->add( k_spell_chain_lightning );
	list->add( k_spell_disintegrate );
	return list;
}

// ---------------------------------------------------------
// get an ability
// ---------------------------------------------------------
static t_artifact_effect* get_ability( t_creature_ability ability )
{
	return new t_artifact_prop::t_give_ability( ability, k_artifact_target_hero );
}

// ---------------------------------------------------------
// get an ability
// ---------------------------------------------------------
static t_artifact_effect* get_ability( t_creature_ability ability, t_artifact_target target )
{
	return new t_artifact_prop::t_give_ability( ability, target );
}

// ---------------------------------------------------------
// get an ability
// ---------------------------------------------------------
static t_trait get_logbook()
{
	t_trait traits;

	traits << get_movement( 50, false, true );
	traits << new t_artifact_prop::t_sea_bonus( k_artifact_target_friendly_creatures, 20 );
	return traits;
}

// ---------------------------------------------------------
// get artifact definitions
// ---------------------------------------------------------
static t_trait const* get_definitions( int& size )
{
	static t_trait const k_definitions[] =
	{
		t_trait( k_artifact_adamantine_armor,		get_armor( 500 )),
		t_trait( k_artifact_adamantine_shield,		get_shield( 50 )),
		t_trait( k_artifact_amulet_of_fear,			get_spell_effect( k_spell_fear, 
																	  k_artifact_target_hero )),
		t_trait( k_artifact_amulet_of_the_undertaker, get_skill( k_skill_necromancy, 10 )),
		t_trait( k_artifact_ankh_of_life,			get_skill( k_skill_resurrection, 10 )),
		t_trait( k_artifact_apprentices_handbook,	get_spell_book( 1 )),
		t_trait( k_artifact_archmages_spellbook,	get_spell_book( 5 )),
		t_trait( k_artifact_armor_of_chaos,			get_magic_armor( k_spell_protection_from_order )),
		t_trait( k_artifact_armor_of_darkness,		get_magic_armor( k_spell_protection_from_life )),
		t_trait( k_artifact_armor_of_light,			get_magic_armor( k_spell_protection_from_death )),
		t_trait( k_artifact_armor_of_order,			get_magic_armor( k_spell_protection_from_chaos )),
		t_trait( k_artifact_arrow_of_slaying,		get_ability( k_ability_ranged_giantslayer )),
		t_trait( k_artifact_arrow_of_stunning,		get_ability( k_ability_ranged_stun )),
		t_trait( k_artifact_axe,					get_weapon( true, false, 75 ))
											     <<	get_speed( k_artifact_target_hero, -1 ),
		t_trait( k_artifact_axe_of_legends,			get_weapon( true, false, 75 ))
												<<	get_damage( 40 ),
		t_trait( k_artifact_badge_of_courage,		get_badge_of_courage()),
		t_trait( k_artifact_bag_of_gold,			get_income( k_gold, 500 )),
		t_trait( k_artifact_barbarian_throwing_club, get_ability( k_ability_stunning ))
												<<  get_ability( k_ability_ranged )
												<<	get_ability( k_ability_ranged_stun )
												<<	get_weapon( true, true, 50 ),
		t_trait( k_artifact_binding_liquid,			get_potion( k_spell_bind_flyer )),
//		t_trait( k_artifact_book_of_enchantment,	get_supreme_artifact( k_town_order, 
//													k_spell_protection_from_chaos, 
//													k_spell_protection_from_nature )),
		t_trait( k_artifact_boots_of_levitation,    get_spell_effect( k_spell_water_walk, 
													k_artifact_target_hero )),
		t_trait( k_artifact_boots_of_speed,			get_movement( 50, true, false )),
		t_trait( k_artifact_bow_of_the_white_stag,	get_weapon( false, true, 500 ))
												<<	get_ability( k_ability_ranged ),
		t_trait( k_artifact_brazier_of_sulfur,		get_income( k_sulfur, 1 )),
		t_trait( k_artifact_breastplate_of_regeneration, get_armor( 200 ))
												 << get_ability( k_ability_regeneration ),
		t_trait( k_artifact_brimstone_breastplate,	get_magic_armor( k_spell_fire_shield )),
		t_trait( k_artifact_caduceus,				get_caduceus() ),
		t_trait( k_artifact_cap_of_knowledge,		get_mana(  5, 1 )),
		t_trait( k_artifact_cape_of_protection,		get_resistance( k_artifact_target_friendly_creatures,
													30 )),
		t_trait( k_artifact_cart_of_lumber,			get_income( k_wood, 2 )),
		t_trait( k_artifact_cart_of_ore,			get_income( k_ore, 2 )),
		t_trait( k_artifact_centaurs_spear,			get_weapon( true, true, 75 ))
												<<	get_ability( k_ability_ranged )
												<<	get_ability( k_ability_normal_melee,
													k_artifact_target_friendly_creatures),
		t_trait( k_artifact_chainmail,				get_armor( 75 ))
												<<	get_combat_movement( k_artifact_target_hero, -300 )
												<<	get_spell_cost_effect( k_artifact_target_hero,
												                           +1, 0 ),
		t_trait( k_artifact_circlet_of_wisdom,		get_mana(  10, 2 )),
		t_trait( k_artifact_cloak_of_confusion,		get_ability( k_ability_ignore_zones_of_control )),
		t_trait( k_artifact_cloud_of_despair,       get_potion( k_spell_despair )),
		t_trait( k_artifact_compass,				get_movement( 50, false, true )),
		t_trait( k_artifact_cowl_of_resistance,		get_resistance( k_artifact_target_hero, 50 )),
		t_trait( k_artifact_crest_of_valor,			get_morale( 1 )),
		t_trait( k_artifact_crossbow,				get_weapon( false, true, 30 ))
										         << get_ability( k_ability_long_range )
												 << get_ability( k_ability_ranged ),
		t_trait( k_artifact_crown_of_the_mind,		get_ability( k_ability_negate_mind_immunity )),
		t_trait( k_artifact_crystal_of_light,		get_scouting( 2 )),
		t_trait( k_artifact_crystal_of_memory,		get_immunity( k_spell_forgetfulness )),
		t_trait( k_artifact_cube_of_crystals,		get_income( k_crystal, 1 )),
		t_trait( k_artifact_davids_sling,			get_ability( k_ability_ranged_giantslayer, 
													k_artifact_target_friendly_creatures ))
												<<	get_ability( k_ability_ranged ),
		t_trait( k_artifact_demon_slayer,			new t_artifact_prop::t_demonslayer(
														true, true, 
														k_artifact_target_friendly_creatures, 50 ))
												<<	get_sword( 30, 30 ),
		t_trait( k_artifact_demonary,				get_demonary() ),
		t_trait( k_artifact_dragon_scale_armor,		get_armor( 250 ))
												<<  get_spell_effect( k_spell_fire_resistance, 
																	  k_artifact_target_hero ),
		t_trait( k_artifact_dragon_scale_shield,	get_shield( 25 ))
												<<  get_spell_effect( k_spell_fire_resistance, 
														k_artifact_target_friendly_creatures,
														0 ),
		t_trait( k_artifact_druids_chain,			get_skill( k_skill_recruitment, 1 )),
		t_trait( k_artifact_dwarven_hammer,			get_weapon( true, false, 100 )),
		t_trait( k_artifact_dwarven_shield,			get_shield( 20 )),
		t_trait( k_artifact_elven_chainmail,		get_armor( 100 )),
		t_trait( k_artifact_emerald_longbow,		get_weapon( false, true, 300 ))
												<<	get_ability( k_ability_ranged ),
		t_trait( k_artifact_equestrians_gloves,		get_movement( 25, true, false )),
		t_trait( k_artifact_fireproof_boots,		get_terrain( k_terrain_lava )),
		t_trait( k_artifact_fizbin_of_misfortune,   get_spell_effect( k_spell_misfortune, 
														k_artifact_target_enemy_creatures, 0 ))
												<<  get_spell_effect( k_spell_misfortune,
														k_artifact_target_enemy_heroes, 0 ),
		t_trait( k_artifact_flaming_arrow,			get_ability( k_ability_area_effect )),
		t_trait( k_artifact_flaming_sword,			get_sword( 30, 30 ))
												<<  get_magic_weapon( 40, 4, 1, true, false,
																 k_damage_fire ),
		t_trait( k_artifact_flask_of_mercury,		get_income( k_mercury, 1 )),
		t_trait( k_artifact_four_leaf_clover,		get_luck( 1 )),
		t_trait( k_artifact_gamblers_deck,			get_luck( 1 )),
		t_trait( k_artifact_giant_slayer,			get_sword( 30, 30 )) 
												<<	get_ability( k_ability_melee_giantslayer ),
		t_trait( k_artifact_gias_gems,				get_income( k_gems, 1 )),
		t_trait( k_artifact_golden_plate_mail,		get_armor( 250 ))
												<<  get_spell_cost_effect( k_artifact_target_hero, 
													1, 0 ),
		t_trait( k_artifact_greater_ring_of_vulnerability, get_ability( k_ability_spell_vulnerability,
													k_artifact_target_everything )),
		t_trait( k_artifact_greatsword,				get_weapon( true, false, 125 )),
		t_trait( k_artifact_gryphonhearts_plate_mail, get_armor( 300 )),
		t_trait( k_artifact_guildmasters_compendium, get_spell_book( 4 )),
		t_trait( k_artifact_halberd_of_speed,		get_speed( k_artifact_target_hero, 2 ))
							<<	get_ability( k_ability_first_strike_immunity )
							<<	get_ability( k_ability_long_weapon )
							<<	get_weapon( true, false, 250 ),
		t_trait( k_artifact_hawkins_bow_of_speed,   get_weapon( false, true, 50 ))
												<<	get_ability( k_ability_ranged )
												<<	get_ability( k_ability_extra_ranged_attack,
													k_artifact_target_friendly_creatures ),
		t_trait( k_artifact_helm_of_command,		get_damage( 20 )) << get_defense( 20 )
									<<	get_speed( k_artifact_target_friendly_creatures, 1 ),
		t_trait( k_artifact_helm_of_power,			get_mana( 20, 4 )),
		t_trait( k_artifact_helm_of_vision,			get_immunity( k_spell_blind )),
		t_trait( k_artifact_hideous_mask,			get_ability( k_ability_panic )),
		t_trait( k_artifact_holy_water,				get_potion( k_spell_holy_water )),
		t_trait( k_artifact_horseshoe,				get_luck( 1 )),
		t_trait( k_artifact_journeymans_notebook,	get_spell_book( 2 )),
		t_trait( k_artifact_kreegan_fire,			get_potion( k_spell_fireball )),
		t_trait( k_artifact_leather_armor,			get_armor( 50 )),
		t_trait( k_artifact_leprechauns_ring,		get_luck( 2 )),
		t_trait( k_artifact_lesser_ring_of_vulnerability, get_ability( k_ability_ignore_wards )),
		t_trait( k_artifact_lions_shield_of_courage, get_shield( 40 )),
		t_trait( k_artifact_logbook_of_the_master_sailor, get_logbook() ),
		t_trait( k_artifact_longbow,				get_weapon( false, true, 50 ))
												 << get_ability( k_ability_ranged ),
		t_trait( k_artifact_longsword,				get_sword( 30, 30 )),
		t_trait( k_artifact_mages_robe,				get_spell_cost_effect( k_artifact_target_hero, 
													-1, 0 )),
		t_trait( k_artifact_mages_staff,			get_spell_cost_effect( k_artifact_target_hero,
													-1, 0 )),
		t_trait( k_artifact_magic_amplifier,		get_spell_cost_effect(
													k_artifact_target_friendly_creatures,
													0, -33 )),
		t_trait( k_artifact_mantle_of_spell_turning, get_resistance( k_artifact_target_hero, 70 )),
		t_trait( k_artifact_marantheas_mug,			get_morale( 3 )),
		t_trait( k_artifact_masters_journal,		get_spell_book( 3 )),
		t_trait( k_artifact_medal_of_honor,			get_morale( 2 )),
		t_trait( k_artifact_mind_shield,			get_mind_shield()),
		t_trait( k_artifact_minotaurs_battleax,		get_weapon( true, false, 500 )),
		t_trait( k_artifact_mirror_of_spell_turning, get_spell_effect( k_spell_magic_mirror, 
														k_artifact_target_hero )),
		t_trait( k_artifact_monks_mace,				get_damage( 30 )),
		t_trait( k_artifact_mullichs_helm_of_leadership, get_morale(2)) 
												<<	get_speed( k_artifact_target_friendly_creatures, 1 ),
		t_trait( k_artifact_necklace_of_charm,		get_skill( k_skill_charm, 5 )),
		t_trait( k_artifact_neeners_invulnerable_cloak, get_resistance( k_artifact_target_hero, 100 )),
		t_trait( k_artifact_nomad_blackbow,			get_weapon( false, true, 200 ))
												<<	get_ability( k_ability_ranged ),
		t_trait( k_artifact_ogs_sandals,			get_terrain( k_terrain_rough )),
		t_trait( k_artifact_orb_of_summoning,		get_supreme_artifact( k_town_order, 
													k_spell_protection_from_chaos, 
													k_spell_protection_from_nature )),
		t_trait( k_artifact_parchment,				new t_artifact_prop::t_learn_spell( 
													k_spell_magic_arrow, k_artifact_target_hero )),
		t_trait( k_artifact_plate_mail,				get_armor( 100 ))
												<<	get_combat_movement( k_artifact_target_hero, -600 )
												<<	get_spell_cost_effect( k_artifact_target_hero,
												                           +2, 0 ),
		t_trait( k_artifact_poison_arrow,			get_spell_attack( k_spell_poison, false, true )),
		t_trait( k_artifact_poison_ring,			get_spell_attack( k_spell_poison, true, false )),
		t_trait( k_artifact_potion_of_cold,			get_potion( k_spell_freezing_attack )),
		t_trait( k_artifact_potion_of_endurance,	get_potion( k_spell_endurance )),
		t_trait( k_artifact_potion_of_fire_resistance, get_potion( k_spell_fire_resistance )),
		t_trait( k_artifact_potion_of_healing,		get_potion( k_spell_simple_healing )),
		t_trait( k_artifact_potion_of_health,		get_potion( k_spell_health_boost )),
		t_trait( k_artifact_potion_of_luck,			get_potion( k_spell_fortune )),
		t_trait( k_artifact_potion_of_mana,			get_potion( k_spell_mana )),
		t_trait( k_artifact_potion_of_mirth,		get_potion( k_spell_spiritual_fervor )),
		t_trait( k_artifact_potion_of_immortality,	get_potion( k_spell_immortality )),
		t_trait( k_artifact_potion_of_quickness,	get_potion( k_spell_quickness )),
		t_trait( k_artifact_potion_of_resistance,	get_potion( k_spell_magic_resistance )),
		t_trait( k_artifact_potion_of_restoration,  get_potion( k_spell_exorcism )),
		t_trait( k_artifact_potion_of_speed,		get_potion( k_spell_speed )),
		t_trait( k_artifact_potion_of_strength,		get_potion( k_spell_strength )),
		t_trait( k_artifact_purse_of_gold,			get_income( k_gold, 250 )),
		t_trait( k_artifact_purse_of_pennypinching, new t_artifact_prop::t_creature_discount( k_artifact_target_hero, 10 )),
//		k_artifact_rangers_mocassins,
		t_trait( k_artifact_ring_of_elementals,		get_elemental_ring() ),
		t_trait( k_artifact_ring_of_health,			get_health( 50 )),
		t_trait( k_artifact_ring_of_permanency,		get_ring_of_permanency() ),
		t_trait( k_artifact_ring_of_protection,		get_defense( 20 )),
		t_trait( k_artifact_ring_of_regeneration,	get_ability( k_ability_regeneration )),
		t_trait( k_artifact_ring_of_speed,			get_speed( k_artifact_target_friendly_creatures, 2 ))
												<<  get_speed( k_artifact_target_hero, 2 ),
		t_trait( k_artifact_ring_of_strength,		get_weapon( true, true, 50 )),
		t_trait( k_artifact_robe_of_the_guardian,	new t_artifact_prop::t_guardian( 
													k_artifact_target_hero, 3 )),
//		t_trait( k_artifact_rod_of_chaos,			get_supreme_artifact( k_town_chaos,
//													k_spell_protection_from_order,
//													k_spell_protection_from_life )),
		t_trait( k_artifact_sack_of_gold,			get_income( k_gold, 750 )),
		t_trait( k_artifact_sandwalker_sandals,		get_terrain( k_terrain_sand )),
		t_trait( k_artifact_scale_mail_of_strength,	get_armor( 100 )) 
												<<	get_weapon( true, true, 100 ),
		t_trait( k_artifact_scroll,					get_scroll( k_spell_magic_arrow )),
		t_trait( k_artifact_seamans_hat,			new t_artifact_prop::t_seamanship(
														k_artifact_target_hero )),
		t_trait( k_artifact_shackles_of_war,		new t_artifact_prop::t_prohibits_retreat(
														k_artifact_target_everything )),
		t_trait( k_artifact_shield,					get_armor( 30 )),
		t_trait( k_artifact_shield_of_chaos,		get_magic_shield( k_spell_protection_from_order )),
		t_trait( k_artifact_shield_of_darkness,		get_magic_shield( k_spell_protection_from_life )),
		t_trait( k_artifact_shield_of_light,		get_magic_shield( k_spell_protection_from_death )),
		t_trait( k_artifact_shield_of_order,		get_magic_shield( k_spell_protection_from_chaos )),
//		t_trait( k_artifact_shield_of_resistance,	get_shield_of_resistance()),
		t_trait( k_artifact_snipers_crossbow,		get_ability( k_ability_long_range,
													k_artifact_target_friendly_creatures ))
												<<	get_ability( k_ability_ranged )
												<<  get_ability( k_ability_long_range )
												<<  get_weapon( false, true, 30 ),
		t_trait( k_artifact_snowshoes,				get_terrain( k_terrain_snow )),
		t_trait( k_artifact_soul_stealer,			get_sword( 40, 40 ))
												<<	get_ability( k_ability_vampire ),
		t_trait( k_artifact_spiders_silk_arrow,		get_spell_attack( k_spell_bind_flyer, false,
													true )),
		t_trait( k_artifact_staads_scarab_of_summoning, get_summoning_scarab()),
		t_trait( k_artifact_staff_of_death,			get_staff_of_death()),
		t_trait( k_artifact_staff_of_enchantment,	get_staff_of_enchantment()),
		t_trait( k_artifact_staff_of_power,			get_spell_cost_effect( k_artifact_target_hero,
													0, -33 )),
		t_trait( k_artifact_staff_of_summoning,		get_staff_of_summoning()),
		t_trait( k_artifact_staff_of_the_witch_king, get_staff_of_the_witch_king()),
		t_trait( k_artifact_statesmans_medal,		get_skill( k_skill_diplomacy, 10 )),
		t_trait( k_artifact_statue_of_legion,		get_statue( 100 )),
		t_trait( k_artifact_steadfast_shield,		get_shield( 30 )),
		t_trait( k_artifact_supreme_crown_of_the_magi, get_mana( 50, 10 )),
		t_trait( k_artifact_surefooted_boots,		get_terrain( k_terrain_rough ))
												<<  get_terrain( k_terrain_swamp )
												<<  get_terrain( k_terrain_lava )
												<<  get_terrain( k_terrain_snow )
												<<  get_terrain( k_terrain_sand )
												<<  get_terrain( k_terrain_water_river )
												<<  get_terrain( k_terrain_ice_river ),
		t_trait( k_artifact_swamp_boots,			get_terrain( k_terrain_swamp )),
		t_trait( k_artifact_sword_of_swiftness,		get_sword( 60, 60 ))
												<<  get_ability( k_ability_extra_melee_attack ),
		t_trait( k_artifact_sword_of_the_gods,		get_sword( 30, 30 )) << get_damage( 50 ),
		t_trait( k_artifact_tavins_sling,			get_weapon( false, true, 100 ))
												<<	get_ability( k_ability_ranged ),
		t_trait( k_artifact_telescope,				get_scouting( 1 )),
		t_trait( k_artifact_throwing_spear,			get_weapon( true, true, 75 )) 
												<<	get_ability( k_ability_ranged ),
		t_trait( k_artifact_thunder_hammer,			get_weapon( true, false, 75 ))
												<<	get_magic_weapon( 70, 7, 1, true, false,
																	  k_damage_lightning ),
		t_trait( k_artifact_tome_of_chaos,			get_spell_book( k_town_chaos )),
		t_trait( k_artifact_tome_of_death,			get_spell_book( k_town_death )),
		t_trait( k_artifact_tome_of_life,			get_spell_book( k_town_life )),
		t_trait( k_artifact_tome_of_nature,			get_spell_book( k_town_nature )),
		t_trait( k_artifact_tome_of_order,			get_spell_book( k_town_order )),
		t_trait( k_artifact_tynans_dagger_of_despair,	get_spell_attack( k_spell_sorrow, true, 
															false )),
		t_trait( k_artifact_unnatural_armor,		get_magic_armor( k_spell_protection_from_nature )),
		t_trait( k_artifact_unnatural_shield,		get_magic_shield( k_spell_protection_from_nature )),
		t_trait( k_artifact_valders_bow_of_sloth,	get_weapon( false, true, 50 ))
												<<	get_ability( k_ability_ranged )
												<<	get_spell_attack( k_spell_slow, false,
																	  true ),
		t_trait( k_artifact_vampiric_amulet,		get_supreme_artifact( k_town_death, 
													k_spell_protection_from_life,
													k_spell_protection_from_nature )),
		t_trait( k_artifact_vial_of_acid,			get_potion( k_spell_acid )),
		t_trait( k_artifact_vial_of_blinding_smoke,	get_potion( k_spell_smoke )),
		t_trait( k_artifact_vial_of_choking_gas,	get_potion( k_spell_gas )),
		t_trait( k_artifact_vial_of_poison,			get_potion( k_spell_poison_attack )),
		t_trait( k_artifact_victory_banner,			get_morale( 1 )),
		t_trait( k_artifact_wand_of_animate_dead,	get_spell_charges( k_spell_animate_dead )),
		t_trait( k_artifact_wand_of_bless,			get_spell_charges( k_spell_bless )),
		t_trait( k_artifact_wand_of_curse,			get_spell_charges( k_spell_curse )),
		t_trait( k_artifact_wand_of_fire,			get_spell_charges( k_spell_fire_bolt )),
		t_trait( k_artifact_wand_of_fireball,		get_spell_charges( k_spell_fireball )),
		t_trait( k_artifact_wand_of_haste,			get_spell_charges( k_spell_haste )),
		t_trait( k_artifact_wand_of_healing,		get_spell_charges( k_spell_heal )),
		t_trait( k_artifact_wand_of_ice,			get_spell_charges( k_spell_ice_bolt )),
		t_trait( k_artifact_wand_of_illusion,		get_spell_charges( k_spell_illusionary_ally )),
		t_trait( k_artifact_wand_of_weakness,		get_spell_charges( k_spell_weakness )),
		t_trait( k_artifact_warding_robe,			get_resistance( k_artifact_target_hero, 30 )),
		t_trait( k_artifact_warlords_ring,			get_damage( 20 )),
		t_trait( k_artifact_winged_sandals,			get_combat_movement( 
													k_artifact_target_friendly_creatures, 600 )),
		t_trait( k_artifact_wizards_ring,			get_mana( 5, 1 )),

//		t_trait( k_artifact_binding,				get_fragment( k_artifact_book_of_enchantment, 5 )),
//		t_trait( k_artifact_chapter_one,			get_fragment( k_artifact_book_of_enchantment, 5 )),
//		t_trait( k_artifact_chapter_two,			get_fragment( k_artifact_book_of_enchantment, 5 )),
//		t_trait( k_artifact_chapter_three,			get_fragment( k_artifact_book_of_enchantment, 5 )),
//		t_trait( k_artifact_chapter_four,			get_fragment( k_artifact_book_of_enchantment, 5 )),
//		t_trait( k_artifact_chain,					get_fragment( k_artifact_vampiric_amulet, 5 )),
//		t_trait( k_artifact_dark_ruby,				get_fragment( k_artifact_vampiric_amulet, 5)),
//		t_trait( k_artifact_left_onyx,				get_fragment( k_artifact_vampiric_amulet, 5)),
//		t_trait( k_artifact_right_onyx,				get_fragment( k_artifact_vampiric_amulet, 5)),
//		t_trait( k_artifact_setting,				get_fragment( k_artifact_vampiric_amulet, 5)),
//		t_trait( k_artifact_blank_shield,			get_fragment( k_artifact_shield_of_resistance, 5 )),
//		t_trait( k_artifact_left_elephant_tusk,		get_fragment( k_artifact_shield_of_resistance, 5 )),
//		t_trait( k_artifact_rhino_horn,				get_fragment( k_artifact_shield_of_resistance, 5 )),
//		t_trait( k_artifact_right_elephant_tusk,	get_fragment( k_artifact_shield_of_resistance, 5 )),
//		t_trait( k_artifact_rising_sun,				get_fragment( k_artifact_shield_of_resistance, 5 )),
//		t_trait( k_artifact_box,					get_fragment( k_artifact_orb_of_summoning, 5 )),
//		t_trait( k_artifact_ebony_key,				get_fragment( k_artifact_orb_of_summoning, 5 )),
//		t_trait( k_artifact_ivory_key,				get_fragment( k_artifact_orb_of_summoning, 5 )),
//		t_trait( k_artifact_mahogany_key,			get_fragment( k_artifact_orb_of_summoning, 5 )),
//		t_trait( k_artifact_sandalwood_key,			get_fragment( k_artifact_orb_of_summoning, 5 )),
//		t_trait( k_artifact_holy_crown,				get_supreme_artifact( k_town_life,
//													k_spell_protection_from_death,
//													k_spell_protection_from_chaos )),
//		t_trait( k_artifact_crown,					get_fragment( k_artifact_holy_crown, 5 )),
//		t_trait( k_artifact_emerald,				get_fragment( k_artifact_holy_crown, 5 )),
//		t_trait( k_artifact_pearl,					get_fragment( k_artifact_holy_crown, 5 )),
//		t_trait( k_artifact_ruby,					get_fragment( k_artifact_holy_crown, 5 )),
//		t_trait( k_artifact_sapphire,				get_fragment( k_artifact_holy_crown, 5 )),
//		t_trait( k_artifact_rams_horn,				get_fragment( k_artifact_rod_of_chaos, 5 )),
//		t_trait( k_artifact_crown_of_dragon_teeth,  get_fragment( k_artifact_rod_of_chaos, 5 )),
//		t_trait( k_artifact_fire_snake,				get_fragment( k_artifact_rod_of_chaos, 5 )),
//		t_trait( k_artifact_infant_dragon_wings,	get_fragment( k_artifact_rod_of_chaos, 5 )),
//		t_trait( k_artifact_vial_of_sulfur,			get_fragment( k_artifact_rod_of_chaos, 5 )),
		t_trait( k_artifact_arms_of_legion,			get_statue_piece( 2, 50 )),
		t_trait( k_artifact_head_of_legion,			get_statue_piece( 3, 50 )),
		t_trait( k_artifact_legs_of_legion,			get_statue_piece( 0, 50 )),
		t_trait( k_artifact_torso_of_legion,		get_statue_piece( 1, 50 )),

		t_trait( k_artifact_breeze_the_falcon,		get_scouting( 1 )),
		t_trait( k_artifact_deadwood_staff,			get_spell_charges( k_spell_hand_of_death, 1, 4 )),
		t_trait( k_artifact_true_gryphonheart_blade,	get_sword( 80, 80 )) 
												<<		get_damage( 40 ),
		t_trait( k_artifact_false_gryphonheart_blade,	get_sword( 80, 80 )),
		t_trait( k_artifact_grail,				new t_artifact_prop::t_grail_building)
	};

	size = ELEMENTS_OF( k_definitions );
	return k_definitions;
};

// ---------------------------------------------------------
// get artifact effects
// ---------------------------------------------------------
t_artifact_effect_list const& get_effects( t_artifact_type type )
{
	static bool initialized = false;
	static t_artifact_effect_list k_effects[k_artifact_type_count];

	if (!initialized)
	{
		int				i;
		int				size;
		t_trait const*  traits = get_definitions( size );

		initialized = true;
		for (i = 0; i < size; i++)
			k_effects[traits[i].get_type()] = traits[i].get_effects();
	}
	return k_effects[type];
}

t_artifact get_default_artifact( t_artifact_type type )
{
	t_artifact result;

	result.set_name( get_name( type ) );
	result.set_name_with_article( get_name( type, true ));
	result.set_help_text( get_help_text( type ));
	result.set_pickup_text( get_pickup_text( type ) );
	result.set_icon( type );
	result.set_effects( get_effects( type ) );
	result.set_level( get_level( type ));
	return result;
}

// -------------------------------------------------------------------
// get a standard scroll 
// -------------------------------------------------------------------
t_artifact get_scroll_artifact( t_spell spell )
{
	t_artifact result;
	t_trait    traits = get_scroll( spell );
	char const* spell_name = get_spell_name( spell );
	int         spell_level = get_spell_level( spell );
	t_keyword_replacer replacer;

	static t_artifact_level const levels[] =
	{ k_artifact_level_treasure, k_artifact_level_treasure, k_artifact_level_minor, 
	  k_artifact_level_major,	 k_artifact_level_major };

	replacer.add_keyword( "%spell_name", spell_name );
	result.set_name( replacer( get_name( k_artifact_scroll ) ));
	result.set_name_with_article( replacer( get_name( k_artifact_scroll, true ) ));
	result.set_help_text( replacer( get_help_text( k_artifact_scroll ) ));
	result.set_pickup_text( replacer( get_pickup_text( k_artifact_scroll ) ));
	result.set_icon( k_artifact_scroll );
	result.set_effects( traits.get_effects() );
	result.set_level( levels[spell_level - 1] );
	return result;
}

// -------------------------------------------------------------------
// get a standard parchment
// -------------------------------------------------------------------
t_artifact get_parchment( t_spell spell )
{
	t_artifact			result;
	t_trait				traits;
	char const*			spell_name = get_spell_name( spell );
	int					spell_level = get_spell_level( spell );
	t_keyword_replacer	replacer;
	static t_artifact_level const levels[] =
	{ k_artifact_level_treasure, k_artifact_level_treasure, k_artifact_level_treasure,
	  k_artifact_level_minor,    k_artifact_level_minor };
	
	replacer.add_keyword( "%spell_name", spell_name );
	traits << get_parchment_effect( spell );
	result.set_name( replacer( get_name( k_artifact_parchment ) ));
	result.set_name_with_article( replacer( get_name( k_artifact_parchment, true ) ) );
	result.set_help_text( replacer( get_help_text( k_artifact_parchment ) ));
	result.set_pickup_text( replacer( get_pickup_text( k_artifact_parchment ) ));
	result.set_icon( k_artifact_parchment );
	result.set_effects( traits.get_effects() );
	result.set_level( levels[spell_level - 1] );
	return result;
}

// -------------------------------------------------------------------
// -------------------------------------------------------------------
bool read_from_map( std::streambuf & stream, t_artifact & artifact )
{
	t_artifact_type artifact_type = t_artifact_type( get< t_uint16 >( stream ) );
	if ( artifact_type < 0 || artifact_type > k_artifact_type_count )
		return false;

	if ( artifact_type == k_artifact_scroll || artifact_type == k_artifact_parchment )
	{
		t_spell spell = t_spell( get< t_uint16 >( stream ) );
		if ( spell < 0 || spell > k_spell_count )
			return false;

		if (artifact_type == k_artifact_scroll)
			artifact = get_scroll_artifact( spell );
		else
			artifact = get_parchment( spell );
		return true;
	}

	artifact = get_default_artifact( artifact_type );

	return true;
}

namespace
{
	typedef t_artifact_trait<t_hero_class> t_class_trait;
};

static t_artifact_effect* get_illusionist_ability()
{
	t_artifact_prop::t_spell_bonus* result;

	result = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, 20 );

	result->add( k_spell_illusionary_ally );
	result->add( k_spell_clone );
	
	return result;
}

static t_artifact_effect* get_archmage_ability()
{
	t_artifact_prop::t_spell_bonus* result;
	t_spell							spell;

	result = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, 20 );

	for (spell = t_spell(0); spell != k_spell_count; enum_incr( spell ))
	{
		if (has_strength( spell ))
			result->add( spell );
	}
	return result;
}

static t_trait_base get_battle_mage_ability()
{
	t_trait_base					result;
	t_artifact_prop::t_spell_bonus* bonus;

	bonus = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, 20 );

	bonus->add( k_spell_magic_fist );
	bonus->add( k_spell_ice_bolt );

	t_artifact_prop::t_spell_book* list 
		= new t_artifact_prop::t_spell_book( k_artifact_target_hero );
	
	list->add( k_spell_magic_fist );
	result << bonus;
	result << list;
	return result;
}

static t_trait_base get_beastmaster_ability()
{
	t_trait_base					result;
	t_artifact_prop::t_spell_bonus* bonus;

	bonus = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, 20 );

	bonus->add( k_spell_summon_wolf );

	t_artifact_prop::t_spell_book* list 
		= new t_artifact_prop::t_spell_book( k_artifact_target_hero );
	
	list->add( k_spell_summon_wolf );
	result << bonus;
	result << list;
	return result;
}

static t_trait_base get_beast_lord_ability()
{
	t_trait_base					result;
	t_artifact_prop::t_spell_bonus* bonus;

	bonus = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, 20 );

	bonus->add( k_spell_summon_wolf );
	bonus->add( k_spell_summon_white_tiger );

	t_artifact_prop::t_spell_book* list 
		= new t_artifact_prop::t_spell_book( k_artifact_target_hero );
	
	list->add( k_spell_summon_wolf );
	result << bonus;
	result << list;
	return result;
}


static t_trait_base get_fire_diviner_ability()
{
	t_artifact_prop::t_spell_bonus* result;
	t_spell							spell;

	result = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, 20 );

	for (spell = t_spell(0); spell != k_spell_count; enum_incr( spell ))
	{
		if (has_strength( spell ) && is_fire( spell ))
			result->add( spell );
	}
	return result;
}

static t_trait_base get_enchanter_ability()
{
	t_artifact_prop::t_spell_bonus* result;
	t_spell							spell;

	result = new t_artifact_prop::t_spell_bonus( k_artifact_target_hero, 20 );

	for (spell = t_spell(0); spell != k_spell_count; enum_incr( spell ))
	{
		if (has_strength( spell ) && is_summoning( spell ))
			result->add( spell );
	}
	return result;
}


static t_class_trait const* get_class_definitions( int& size )
{
	static t_class_trait const k_definitions[] =
	{
		t_class_trait( k_hero_class_general,		get_morale( 1 )),
		t_class_trait( k_hero_class_field_marshal,	get_damage( 10 )),
		t_class_trait( k_hero_class_lord_commander,	get_morale( 2 )),
		t_class_trait( k_hero_class_crusader,		get_spell_effect( k_spell_spiritual_fervor )),
		t_class_trait( k_hero_class_illusionist,	get_illusionist_ability()),
		t_class_trait( k_hero_class_reaver,			get_spell_effect( k_spell_bloodlust )),
		t_class_trait( k_hero_class_pyromancer,		get_ability( k_ability_fire_shield )),
		t_class_trait( k_hero_class_warden,			get_defense( 10 )),
		t_class_trait( k_hero_class_archmage,		get_archmage_ability()),

		t_class_trait( k_hero_class_ranger,			get_weapon( false, true, 50 ))
												<<	get_ability( k_ability_ranged ),
		t_class_trait( k_hero_class_warlord,		get_weapon( true, false, 50 )),
		t_class_trait( k_hero_class_paladin,		get_ability( k_ability_death_protection )),
		t_class_trait( k_hero_class_battle_mage,	get_battle_mage_ability()),
		t_class_trait( k_hero_class_assassin,		get_spell_effect( k_spell_haste )),
		t_class_trait( k_hero_class_fireguard,		get_ability( k_ability_fire_resistance )),
		t_class_trait( k_hero_class_green_knight,	get_beastmaster_ability()),
		
		t_class_trait( k_hero_class_guildmaster,	get_ability( k_ability_stunning )),
		t_class_trait( k_hero_class_prophet,		get_spell_effect( k_spell_holy_armor )),
		t_class_trait( k_hero_class_seer,			get_scouting(2)),
		t_class_trait( k_hero_class_ninja,			get_ability( k_ability_poison )),
		t_class_trait( k_hero_class_fire_diviner,	get_fire_diviner_ability()),
		t_class_trait( k_hero_class_bard,			get_spell_effect( k_spell_fortune )),

		t_class_trait( k_hero_class_cardinal,		get_skill( k_skill_resurrection, 5 )),
		t_class_trait( k_hero_class_wizard_king,	get_spell_attack( k_spell_misfortune, 
																	  true, true )),
		t_class_trait( k_hero_class_dark_lord,		get_spell_attack( k_spell_sorrow, true, true)),
		t_class_trait( k_hero_class_witch_king,		get_ability( k_ability_panic )),
		t_class_trait( k_hero_class_beast_lord,		get_beast_lord_ability()),

		t_class_trait( k_hero_class_monk,			get_ability( k_ability_chaos_protection )),
		t_class_trait( k_hero_class_dark_priest,	get_ability( k_ability_vampire )),
		t_class_trait( k_hero_class_heretic,		get_ability( k_ability_ignore_wards )),
		t_class_trait( k_hero_class_summoner,		get_skill( k_skill_recruitment, 1 )),

		t_class_trait( k_hero_class_shadow_mage,	get_spell_effect( k_spell_blur )),
		t_class_trait( k_hero_class_wizard,			get_spell_cost_effect( k_artifact_target_hero,
													-2, 0 )),
		t_class_trait( k_hero_class_enchanter,		get_enchanter_ability()),

		t_class_trait( k_hero_class_lich,			get_ability( k_ability_aging )),
		t_class_trait( k_hero_class_demonologist,	get_demonary( 50 )),

		t_class_trait( k_hero_class_warlock,		get_mana( 10, 1 )),
	};

	size = ELEMENTS_OF( k_definitions );
	return k_definitions;
}

// ---------------------------------------------------------
// get artifact effects
// ---------------------------------------------------------
t_artifact_effect_list const& get_class_effects( t_hero_class hero_class )
{
	static bool initialized = false;
	static t_artifact_effect_list k_effects[k_hero_class_count];

	if (!initialized)
	{
		int						i;
		int						size;
		t_class_trait const*	traits = get_class_definitions( size );

		initialized = true;
		for (i = 0; i < size; i++)
			k_effects[traits[i].get_type()] = traits[i].get_effects();
	}
	return k_effects[hero_class];
}

t_artifact get_class_ability( t_hero_class hero_class )
{
	t_artifact						result;
	t_artifact_effect_list const&	effects = get_class_effects( hero_class );

	if (effects.empty())
		return result;

	result.set_icon( k_artifact_shield );
	result.set_effects( effects );
	return result;
}
